// Copyright 2021 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package testutil

import (
	"github.com/matrixorigin/matrixone/pkg/common/mpool"
	"github.com/matrixorigin/matrixone/pkg/container/nulls"
	"github.com/matrixorigin/matrixone/pkg/container/types"
	"github.com/matrixorigin/matrixone/pkg/container/vector"
)

// All vectors generated by the Make Function, their memory is not allocated through the memory pool
// if you want to generate a vector in memory pool, use NewFunction to instead of MakeFunction.
var (
	TestUtilMp = mpool.MustNewZeroNoFixed()

	MakeInt64Vector = func(values []int64, nsp []uint64) *vector.Vector {
		return makeVector(values, nsp, int64Type)
	}

	MakeInt32Vector = func(values []int32, nsp []uint64) *vector.Vector {
		return makeVector(values, nsp, int32Type)
	}

	MakeInt16Vector = func(values []int16, nsp []uint64) *vector.Vector {
		return makeVector(values, nsp, int16Type)
	}

	MakeRowIdVector = func(values []types.Rowid, nsp []uint64) *vector.Vector {
		return makeVector(values, nsp, rowIdType)
	}

	MakeInt8Vector = func(values []int8, nsp []uint64) *vector.Vector {
		return makeVector(values, nsp, int8Type)
	}

	MakeUint16Vector = func(values []uint16, nsp []uint64) *vector.Vector {
		return makeVector(values, nsp, uint16Type)
	}

	MakeVarcharVector = func(values []string, nsp []uint64) *vector.Vector {
		return makeStringVector(values, nsp, varcharType)
	}

	MakeTextVector = func(values []string, nsp []uint64) *vector.Vector {
		return makeStringVector(values, nsp, textType)
	}
)

// functions to make a scalar vector for test.
var (
	MakeScalarNull = func(typ types.T, length int) *vector.Vector {
		return vector.NewConstNull(typ.ToType(), length, NewProc().Mp())
	}
	MakeScalarInt64 = func(v int64, length int) *vector.Vector {
		return makeScalar(v, length, int64Type)
	}

	MakeScalarVarchar = func(value string, length int) *vector.Vector {
		return makeScalarString(value, length, varcharType)
	}
)

func makeVector[T types.FixedSizeT](values []T, nsp []uint64, typ types.Type) *vector.Vector {
	vec := vector.NewVec(typ)
	err := vector.AppendFixedList(vec, values, nil, TestUtilMp)
	vec.SetNulls(nulls.Build(len(values), nsp...))

	if err != nil {
		panic(err)
	}
	return vec
}

func makeStringVector(values []string, nsp []uint64, typ types.Type) *vector.Vector {
	var err error

	vec := vector.NewVec(typ)
	if nsp == nil {
		err = vector.AppendStringList(vec, values, nil, TestUtilMp)
	} else {
		err = vector.AppendStringList(vec, values, nil, TestUtilMp)
		vec.SetNulls(nulls.Build(len(values), nsp...))
	}
	if err != nil {
		panic(err)
	}

	return vec
}

func makeScalar[T types.FixedSizeT](value T, length int, typ types.Type) *vector.Vector {
	v, err := vector.NewConstFixed(typ, value, length, TestUtilMp)
	if err != nil {
		panic(err)
	}
	return v
}

func makeScalarString(value string, length int, typ types.Type) *vector.Vector {
	v, err := vector.NewConstBytes(typ, []byte(value), length, TestUtilMp)
	if err != nil {
		panic(err)
	}
	return v
}
